﻿using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Cofe.Core.Property
{
    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class SetFirst : IPropertySetBehavior
    {
        #region Constructor

        public SetFirst()
        {
        }

        #endregion

        #region Methods

        public async Task<bool> SetPropertyAsync(IPropertyProvider[] allPropertyProviders, PropertyPair propertyPair,
            PropertyRetrivalOptions options)
        {
            if (options.HasFlag(PropertyRetrivalOptions.First))
            {
                var property = propertyPair.Property;
                var value = propertyPair.Value;

                foreach (var pp in allPropertyProviders)
                    if (pp.SupportedDefinitions.IsPropertySupported(property) && !pp.IsPropertyReadOnly(property))
                        return await pp.SetPropertyAsync(propertyPair);
                throw new NotSupportedException("Property not supported.");

            }
            return false;
        }

        #endregion

        #region Data

        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyDictionary PropertyDictionary
        {
            get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
            set { _propertyDictionary = value; }
        }


        public PropertyRetrivalOptions SupportOption
        {
            get { return PropertyRetrivalOptions.First; }
        }

        #endregion
    }


    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class SetAggregated : IPropertySetBehavior
    {
        #region Constructor

        public SetAggregated()
        {
        }

        #endregion

        #region Methods

        public async Task<bool> SetPropertyAsync(IPropertyProvider[] allPropertyProviders, PropertyPair propertyPair,
            PropertyRetrivalOptions options)
        {
            if (options.HasFlag(PropertyRetrivalOptions.Aggregate) ||
                options.HasFlag(PropertyRetrivalOptions.Max) || options.HasFlag(PropertyRetrivalOptions.Min))
            {
                var property = propertyPair.Property;
                var value = propertyPair.Value;
                bool valueSet = false;
                bool propSupported = false;
                foreach (var pp in allPropertyProviders)
                    if (pp.SupportedDefinitions.IsPropertySupported(property) && !pp.IsPropertyReadOnly(property))
                    {
                        propSupported = true;
                        bool retVal = await pp.SetPropertyAsync(propertyPair);
                        if (retVal)
                            valueSet = true;
                    }

                if (!propSupported)
                    throw new NotSupportedException("Property not supported.");
                return valueSet;
            }
            return false;
        }

        #endregion

        #region Data

        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyDictionary PropertyDictionary
        {
            get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
            set { _propertyDictionary = value; }
        }


        public PropertyRetrivalOptions SupportOption
        {
            get { return PropertyRetrivalOptions.Aggregate | PropertyRetrivalOptions.Max | PropertyRetrivalOptions.Min; }
        }

        #endregion

    }

    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class SetFirstHandled : IPropertySetBehavior
    {
        #region Constructor

        public SetFirstHandled()
        {
        }

        #endregion

        #region Methods

        public async Task<bool> SetPropertyAsync(IPropertyProvider[] allPropertyProviders, PropertyPair propertyPair,
            PropertyRetrivalOptions options)
        {
            if (options.HasFlag(PropertyRetrivalOptions.HandleOnes) || options.HasFlag(PropertyRetrivalOptions.Default))
            {
                var property = propertyPair.Property;
                var value = propertyPair.Value;
                bool propSupported = false;

                foreach (var pp in allPropertyProviders)
                    if (pp.SupportedDefinitions.IsPropertySupported(property) && !pp.IsPropertyReadOnly(property))
                    {
                        propSupported = true;
                        bool retVal = await pp.SetPropertyAsync(propertyPair);
                        if (retVal)
                            return true;
                    }

                if (!propSupported)
                    throw new NotSupportedException("Property not supported.");

                return false;
            }
            return false;
        }

        #endregion

        #region Data

        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyDictionary PropertyDictionary
        {
            get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
            set { _propertyDictionary = value; }
        }


        public PropertyRetrivalOptions SupportOption
        {
            get { return PropertyRetrivalOptions.HandleOnes | PropertyRetrivalOptions.Default; }
        }

        #endregion

    }


    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class SetCacheOnly : IPropertySetBehavior
    {
        #region Constructor

        public SetCacheOnly()
        {
        }

        #endregion

        #region Methods

        public async Task<bool> SetPropertyAsync(IPropertyProvider[] allPropertyProviders, PropertyPair propertyPair,
            PropertyRetrivalOptions options)
        {
            IPropertyCache propertyCache = allPropertyProviders.FirstOrDefault(pp => pp is IPropertyCache) as IPropertyCache;
            if (propertyCache == null)
                return false;

            await propertyCache.SetPropertyAsync(propertyPair);
            return true;
        }

        #endregion

        #region Data

        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyDictionary PropertyDictionary
        {
            get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
            set { _propertyDictionary = value; }
        }


        public PropertyRetrivalOptions SupportOption
        {
            get { return PropertyRetrivalOptions.CacheOnly; }
        }

        #endregion

    }


    [Export(typeof(ICofeService))]
    [ServicePriority(ServicePriorityAttribute.DefaultPriority_COFE)]
    public class SetIgnoreCache : IPropertySetBehavior
    {
        #region Constructor

        public SetIgnoreCache()
        {
        }

        #endregion

        #region Methods

        public async Task<bool> SetPropertyAsync(IPropertyProvider[] allPropertyProviders, PropertyPair propertyPair,
            PropertyRetrivalOptions options)
        {

            var property = propertyPair.Property;
            var value = propertyPair.Value;
            bool valueSet = false;
            bool propSupported = false;
            foreach (var pp in allPropertyProviders)
                if (!(pp is IPropertyCache))
                    if (pp.SupportedDefinitions.IsPropertySupported(property) && !pp.IsPropertyReadOnly(property))
                    {
                        propSupported = true;
                        bool retVal = await pp.SetPropertyAsync(propertyPair);
                        if (retVal)
                            valueSet = true;
                    }

            if (!propSupported)
                throw new NotSupportedException("Property not supported.");
            return valueSet;
        }

        #endregion

        #region Data

        private IPropertyDictionary _propertyDictionary = null;

        #endregion

        #region Public Properties

        public IPropertyDictionary PropertyDictionary
        {
            get { return _propertyDictionary ?? CofeServices.ServiceLocater.FindService<IPropertyDictionary>(); }
            set { _propertyDictionary = value; }
        }


        public PropertyRetrivalOptions SupportOption
        {
            get { return PropertyRetrivalOptions.Default; }
        }

        #endregion

    }

  
}
